from typing import List, Dict
import re


class Interaction:
    def __init__(self, item_id, user_id, type_id, interaction_type=0, info=None):
        self.item_id = item_id
        self.user_id = user_id
        self.type_id = type_id
        self.interaction_type = interaction_type  # 0: Reader
        self.info = info


class FileLoader:
    def __init__(self, hyper_params):
        self.hyper_params = hyper_params
        self.filename = hyper_params['dataset_path']
        self.book = {}
        self.reader = {}
        self.type = {}
        self.intereaction_list: Dict[int, List[Interaction]] = {}
        self.book_cnt = 0
        self.reader_cnt = 0
        self.type_cnt = 0

        if hyper_params['load_from_file']:
            self.read_from_dataset_file()
        else:
            self.read_from_map_file()
        hyper_params['item_cnt'] = self.book_cnt
        hyper_params['user_cnt'] = self.reader_cnt

    def read_from_map_file(self):
        bind_path = self.hyper_params['bind_file_path']
        bind_book_file = open(bind_path+'bind_book.txt', 'rt')
        bind_user_file = open(bind_path+'bind_user.txt', 'rt')
        book_map_file = open(bind_path+'book_map.txt', 'rt')

        bind_book_dict = {}
        for line in bind_book_file.readlines():
            cur_data = line.rstrip().split(';')
            k, v = int(cur_data[0]), int(cur_data[-1])
            bind_book_dict[k] = v

        bind_user_dict = {}
        for line in bind_user_file.readlines():
            cur_data = line.rstrip().split(';')
            k, v = int(cur_data[0]), int(cur_data[-1])
            bind_user_dict[k] = v

        book_map_dict = {}
        for line in book_map_file.readlines():
            cur_data = line.rstrip().split(';')
            k, isbn, code, title = int(
                cur_data[0]), cur_data[1], cur_data[2], cur_data[3]
            book_map_dict[k] = (isbn, code, title)

        bind_book_file.close()
        bind_user_file.close()

        self.reader_cnt = len(bind_user_dict)
        self.book_cnt = len(bind_book_dict)

        # Read from dataset file
        with open(self.filename, encoding='utf-8', errors='ignore') as file_object:
            for line in file_object.readlines():
                words = line.rstrip().split(';')
                cur_reader_id = int(words[0])
                cur_book_id = int(words[1])

                cur_book_code = book_map_dict[cur_book_id][1]
                cur_type = re.match('[0-9A-Za-z]*', cur_book_code).group()

                if cur_type not in self.type:
                    self.type[cur_type] = self.type_cnt
                    self.type_cnt += 1

                if cur_reader_id not in self.intereaction_list:
                    self.intereaction_list[cur_reader_id] = []

                cur_type_id = self.type[cur_type]

                self.intereaction_list[cur_reader_id].append(
                    Interaction(cur_book_id, cur_reader_id, cur_type_id))

        print(
            f'POP: Reader: {self.reader_cnt}, Book: {self.book_cnt}, Type: {self.type_cnt}')

        self.bind_book_dict = bind_book_dict
        self.bind_user_dict = bind_user_dict
        self.book_map_dict = book_map_dict

    def read_from_dataset_file(self):
        with open(self.filename, encoding='utf-8', errors='ignore') as file_object:
            for line in file_object:
                words = line.split('@')
                if len(words) <= 7:
                    continue

                cur_type = re.match('[0-9A-Za-z]*', words[0]).group()
                if len(cur_type) == 0:
                    continue

                if '50' in words:  # only use borrow cases
                    # use ID and book name as key
                    bookKey = words[0] + '@' + words[1]
                    if bookKey not in self.book:
                        self.book[bookKey] = self.book_cnt
                        self.book_cnt += 1

                    readerKey = words[7]  # use student ID as key
                    if readerKey not in self.reader:
                        self.reader[readerKey] = self.reader_cnt
                        self.reader_cnt += 1

                    if cur_type not in self.type:
                        self.type[cur_type] = self.type_cnt
                        self.type_cnt += 1

                    cur_book_id = self.book[bookKey]
                    cur_reader_id = self.reader[readerKey]
                    cur_type_id = self.type[cur_type]

                    if cur_reader_id not in self.intereaction_list:
                        self.intereaction_list[cur_reader_id] = []

                    self.intereaction_list[cur_reader_id].append(
                        Interaction(cur_book_id, cur_reader_id, cur_type_id))

        print(
            f'POP: Reader: {self.reader_cnt}, Book: {self.book_cnt}, Interact: {len(self.intereaction_list)}, Type: {self.type_cnt}')


if __name__ == '__main__':
    hyper_params = {
        'dataset_path': 'bslen15/dataset_out_2.txt',
        'load_from_file': False,
        'bind_file_path': 'bslen15/'
    }

    file_loader = FileLoader(hyper_params=hyper_params)
